package nqueens.core;

import java.util.Arrays;
import java.util.Random;

import nqueens.algorithm.ObjectiveCalculator;

/**
 * Chromosome for N-Queens problem with Genetic Algorithm.
 * <br>
 * Each queen is set to a different column and the values array 
 * represents the rows attributed for each queen (or column).
 * <br>
 *  All values are in the range [0,numQueens).
 *  
 * @author Artur Alves
 * @author Danilo Torres
 * @author Rodrigo Bruno
 */
public class Chromosome implements Cloneable {

	private int[] values;

	public Chromosome(int[] values) {
		this.values = values;
	}

	public boolean equals(Object o) {
		if (!(o instanceof Chromosome))
			return false;
		Chromosome other = (Chromosome) o;
		return Arrays.equals(values, other.values);
	}

	public int hashCode() {
		return Arrays.hashCode(values);
	}

	public static Chromosome generateRandom(int numQueens) {
		Random r = new Random();
		int[] values = new int[numQueens];
		for (int i = 0; i < numQueens; i++) {
			values[i] = r.nextInt(numQueens);
		}
		return new Chromosome(values);
	}

	public String toString() {
		// TODO: refazer toString para mostrar tabuleiro
		return Arrays.toString(values) + ", obj = " + new ObjectiveCalculator().calcObjective(this);
	}

	public int[] getValues() {
		return values;
	}

	public void setValues(int[] values) {
		this.values = values;
	}

	public String prettyPrint() {
		// TODO: Artur
		String out = "";
		for(int i = 0; i < values.length; i++) {
			out += "------";
		}
		out += "\n";
		
		for(int i = 0; i < values.length; i++) {
			for(int k = 0; k < values.length; k++) {
				if(values[k] == i) {
					for(int j = 0; j < k; j++) {
						out += "|    |";
					}
					out += "| Q  |";
					for(int j = 0; j < (values.length-1) - k; j++) {
						out += "|    |";
					}
					out += "\n";
				}
			}
		}
		
		for(int i = 0; i < values.length; i++) {
			out += "------";
		}
		
		return out;
	}

	public boolean isSolution() {
		for (int i = 0; i < values.length; i++) {
			for (int j = i+1; j < values.length; j++) {
				if (is_attacking(values[i], i, values[j], j))
					return false;
			}
		}
		return true;
	}

	private boolean is_attacking(int i1, int j1, int i2, int j2) {
		return i1 == i2 || j1 == j2 || Math.abs(j2-j1) == Math.abs(i2-i1) || (Math.abs(j2-j1) == -Math.abs(i2-i1));
	}
	
	public Object clone() {
		Chromosome c = new Chromosome(Arrays.copyOf(values, values.length));
		return c;
	}
	
}
